package com.cta.service.impl;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cta.constant.Gender;
import com.cta.constant.ROLE;
import com.cta.dao.SitePersistence;
import com.cta.entity.Contact;
import com.cta.entity.PBX;
import com.cta.entity.PBXFactory;
import com.cta.entity.Role;
import com.cta.entity.ServerConfig;
import com.cta.entity.Site;
import com.cta.exception.CTAServiceException;
import com.cta.service.SiteService;
import com.cta.utils.CodeLookupUtils;
import com.cta.utils.SupportLoaderDelegateAdapter;

@Service("siteService")
@Transactional(readOnly = true)
public class SiteServiceImpl implements SiteService {

	@Autowired
	private SitePersistence sitePersistence;

	@Transactional(readOnly = false)
	public Site createSite(String name, String description, Long parentId) {
		return sitePersistence.save(new Site(name, description, parentId));
	}

	/**
	 * find all Sites
	 * 
	 * @return
	 */
	public List<Site> findAllSites() {
		return sitePersistence.findAllSites();
	}

	/**
	 * find all child site of parent id
	 * 
	 * @param parentId
	 * @return
	 */
	public List<Site> findAllChildSite(Long parentId) {
		return sitePersistence.findAllChildSite(parentId);
	}

	/**
	 * find root site
	 * 
	 * @param parentId
	 * @return
	 */
	public Site findRootSite() {
		return sitePersistence.findRootSite();
	}

	/**
	 * find site by name
	 * 
	 * @param name
	 * @return
	 */
	public Site findSiteByName(String name) {
		return sitePersistence.findSiteByName(name);
	}

	/**
	 * update site base on id
	 * 
	 * @param id
	 * @param name
	 * @param description
	 * @throws CTAServiceException
	 */
	@Transactional(readOnly = false)
	public void updateSite(Long id, String name, String description) throws CTAServiceException {
		Site site = sitePersistence.findById(Site.class, id);
		if (site == null) {
			throw new CTAServiceException("Site is not found");
		}
		site.setName(name);
		site.setDescription(description);
	}

	/**
	 * create contact
	 * 
	 * @param name
	 * @param fullName
	 * @param gender
	 * @param birthday
	 * @param email
	 * @param phone
	 * @param assignTo
	 * @param address
	 * @return
	 */
	@Transactional(readOnly = false)
	public Contact createUser(String name, String station, String authorizationCode, String fullName, String gender,
			String birthday, String email, String mobile, String home, String fax, String password, Long assignTo,
			String address) {
		Role normalRole = sitePersistence.findSingleObject(Role.class, "role", ROLE.CONTACT);
		Contact c = new Contact();
		c.setRole(normalRole);
		c.setName(name);
		c.setFullName(fullName);
		c.setGender(Gender.valueOf(gender));
		c.setBirthDay(birthday);
		c.setEmail(email);
		c.setMobile(mobile);
		c.setAssignTo(assignTo);
		c.setAddress(address);
		c.setStation(station);
		c.setAuthorizationCode(authorizationCode);
		c.setHome(home);
		c.setFax(fax);
		c.setPassword(password);
		return sitePersistence.save(c);
	}

	/**
	 * update contact
	 * 
	 * @param name
	 * @param fullName
	 * @param gender
	 * @param birthday
	 * @param email
	 * @param phone
	 * @param assignTo
	 * @param address
	 * @return
	 */
	@Transactional(readOnly = false)
	public Contact updateUser(Long userId, String name, String station, String authorizationCode, String fullName,
			String gender, String birthday, String email, String mobile, String home, String fax, String password,
			Long assignTo, String address) {
		Contact c = sitePersistence.findById(Contact.class, userId);
		c.setName(name);
		c.setFullName(fullName);
		c.setGender(Gender.valueOf(gender));
		c.setBirthDay(birthday);
		c.setEmail(email);
		c.setMobile(mobile);
		c.setAssignTo(assignTo);
		c.setAddress(address);
		c.setStation(station);
		c.setAuthorizationCode(authorizationCode);
		c.setHome(home);
		c.setFax(fax);
		c.setPassword(password);
		return c;
	}

	/**
	 * find all Contact by parentId( assignTo )
	 * 
	 * @param parentId
	 * @return
	 */
	public List<Contact> findContactByParentId(Long parentId) {
		return sitePersistence.findContactByParentId(parentId);
	}

	/**
	 * find all contact except super admin
	 * 
	 * @return
	 */
	public List<Contact> findAllContactExceptSuperAdminAndNotAssign() {
		return sitePersistence.findAllContactExceptSuperAdminAndNotAssign();
	}

	/**
	 * find all contact except super admin
	 * 
	 * @return
	 */
	public List<Contact> findAllContactExceptSuperAdmin() {
		return sitePersistence.findAllContactExceptSuperAdmin();
	}

	/**
	 * get all admin contact
	 * 
	 * @return
	 */
	public List<Contact> findAllAdminContact() {
		return sitePersistence.findAllAdminContact();
	}

	/**
	 * get all normal contact
	 * 
	 * @return
	 */
	public List<Contact> findAllNormalContact() {
		return sitePersistence.findAllNormalContact();
	}

	/**
	 * create PBX entity
	 * 
	 * @param name
	 * @param description
	 * @param assignTo
	 * @return
	 */
	@Transactional(readOnly = false)
	public PBX createPBX(String pbxNo, String name, String description, Long pbxFactoryId) {
		PBX p = new PBX();
		p.setPbxNo(pbxNo);
		p.setName(name);
		p.setDescription(description);
		p.setPbxFactory(sitePersistence.findById(PBXFactory.class, pbxFactoryId));
		return sitePersistence.save(p);
	}

	/**
	 * update PBX entity
	 * 
	 * @param name
	 * @param description
	 * @param assignTo
	 * @return
	 */
	@Transactional(readOnly = false)
	public void updatePBX(String pbxNo, String name, String description, Long pbxId) throws CTAServiceException {
		PBX p = sitePersistence.findById(PBX.class, pbxId);
		if (p == null) {
			throw new CTAServiceException("PBX not found");
		}
		p.setPbxNo(pbxNo);
		p.setName(name);
		p.setDescription(description);
	}

	/**
	 * find all PBX by parentId (assignTo)
	 * 
	 * @param parentId
	 * @return
	 */
	public List<PBX> findPBXByParentId(Long parentId) {
		return sitePersistence.findPBXByParentId(parentId);
	}

	/**
	 * find contact by id
	 * 
	 * @param userId
	 * @return
	 */
	public Contact findContactById(Long userId) {
		return sitePersistence.findById(Contact.class, userId);
	}

	/**
	 * find pbx by id
	 * 
	 * @param pbxId
	 * @return
	 */
	public PBX findPBXById(Long pbxId) {
		PBX pbx = sitePersistence.findById(PBX.class, pbxId);
		pbx.getPbxFactory().getId();
		return pbx;
	}

	/**
	 * find pbx by factory id
	 * 
	 * @param factoryId
	 * @return
	 */
	public List<PBX> findPBXByFactoryId(Long factoryId) {
		return sitePersistence.findPBXByFactoryId(factoryId);
	}

	/**
	 * find all PBX
	 * 
	 * @param parentId
	 * @return
	 */
	public List<PBX> findAllPBX() {
		return sitePersistence.findAllPBX(new SupportLoaderDelegateAdapter<PBX>() {
			public void load(List<PBX> entities) {
				for (PBX pbx : entities) {
					if (pbx.getPbxFactory() != null) {
						pbx.getPbxFactory().getId();
					}
				}
			}
		});
	}

	/**
	 * find all PBX which are not assign to site node yet.
	 * 
	 * @param parentId
	 * @return
	 */
	public List<PBX> findAllPBXNotAssign() {
		return sitePersistence.findAllPBXNotAssign(new SupportLoaderDelegateAdapter<PBX>() {
			public void load(List<PBX> entities) {
				for (PBX pbx : entities) {
					if (pbx.getPbxFactory() != null) {
						pbx.getPbxFactory().getId();
					}
				}
			}
		});
	}

	/**
	 * assign all pbx to site node
	 * 
	 * @param assignTo
	 * @param itemselector
	 */
	@Transactional(readOnly = false)
	public void assignPBXToSite(Long assignTo, String itemselector) {
		if (StringUtils.isNotEmpty(itemselector)) {
			String[] splits = itemselector.split(",");
			for (String pbxId : splits) {
				if (StringUtils.isNotEmpty(pbxId)) {
					PBX pbx = sitePersistence.findById(PBX.class, Long.valueOf(pbxId));
					if (pbx != null) {
						pbx.setAssignTo(assignTo);
					}
				}
			}
		}
	}

	/**
	 * un assign all pbx to site node
	 * 
	 * @param assignTo
	 * @param itemselector
	 */
	@Transactional(readOnly = false)
	public void unAssignPBXToSite(String pbxIds) {
		if (StringUtils.isNotEmpty(pbxIds)) {
			String[] splits = pbxIds.split(",");
			for (String pbxId : splits) {
				if (StringUtils.isNotEmpty(pbxId.trim())) {
					PBX pbx = sitePersistence.findById(PBX.class, Long.valueOf(pbxId.trim()));
					if (pbx != null) {
						pbx.setAssignTo(null);
					}
				}
			}
		}
	}

	/**
	 * assign all user to site node
	 * 
	 * @param assignTo
	 * @param itemselector
	 */
	@Transactional(readOnly = false)
	public void assignUserToSite(Long assignTo, String itemselector) {
		if (StringUtils.isNotEmpty(itemselector)) {
			String[] splits = itemselector.split(",");
			for (String userId : splits) {
				if (StringUtils.isNotEmpty(userId.trim())) {
					Contact c = sitePersistence.findById(Contact.class, Long.valueOf(userId.trim()));
					if (c != null) {
						c.setAssignTo(assignTo);
					}
				}
			}
		}
	}

	/**
	 * un assign all user to site node, reset role of user to normal
	 * 
	 * @param assignTo
	 * @param itemselector
	 */
	@Transactional(readOnly = false)
	public void unAssignUserToSite(String userIds) {
		if (StringUtils.isNotEmpty(userIds)) {
			String[] splits = userIds.split(",");
			Role normalRole = sitePersistence.findById(Role.class, ROLE.CONTACT.getId());
			for (String userId : splits) {
				if (StringUtils.isNotEmpty(userId.trim())) {
					Contact user = sitePersistence.findById(Contact.class, Long.valueOf(userId.trim()));
					if (user != null) {
						user.setAssignTo(null);
						user.setRole(normalRole);
					}
				}
			}
		}
	}

	/**
	 * set admin for site
	 * 
	 * @param siteId
	 * @param userId
	 * @return
	 */
	@Transactional(readOnly = false)
	public Contact setAsAdminSite(Long siteId, Long oldUserId, Long userId) {
		if (oldUserId != null) {
			if (oldUserId.equals(userId)) {
				return null;
			}
			Contact oldUser = sitePersistence.findById(Contact.class, oldUserId);
			Role normalRole = sitePersistence.findById(Role.class, ROLE.CONTACT.getId());
			oldUser.setRole(normalRole);
		}
		// update new role for new user
		Contact user = sitePersistence.findById(Contact.class, userId);
		Role adminRole = sitePersistence.findById(Role.class, ROLE.ADMIN.getId());
		// set admin
		user.setRole(adminRole);
		// set admin Id insite
		Site site = sitePersistence.findById(Site.class, siteId);
		site.setAdminId(user.getId());
		return user;
	}
	
	public ServerConfig loadConfig(){
		return sitePersistence.loadConfig();
	}
	
	@Transactional(readOnly = false)
	public ServerConfig saveConfig(ServerConfig config){
		CodeLookupUtils.serverConfig = sitePersistence.save(config);
		return CodeLookupUtils.serverConfig;
	}
	
	@Override
	public Contact findContact(String authorization, String callingNumber){
		String sq = "select c from Contact c where ";
		if(StringUtils.isEmpty(authorization) && StringUtils.isEmpty(callingNumber)){
			return null;
		} else if(StringUtils.isEmpty(authorization)){
			sq += "c.station= ?1";
			return sitePersistence.findSingleObject(sq, callingNumber);
		} else if(StringUtils.isEmpty(callingNumber)){
			sq += "c.authorizationCode = ?1";
			return sitePersistence.findSingleObject(sq, authorization);
		} else {
			sq += "c.station= ?1 or c.station= ?2";
			return sitePersistence.findSingleObject(sq, authorization, callingNumber);
		}
	}
}
